﻿using System;
using Microsoft.TeamFoundation.Client;
using System.Net;
using Nuwanda.Common;
using Microsoft.Practices.EnterpriseLibrary.Security.Cryptography;
using Nuwanda.TfsSpotlight.Data;
using Nuwanda.TfsSpotlight.Shell.Services;
using Nuwanda.TfsSpotlight.Shell.Services.Interfaces;
using StructureMap;

namespace Nuwanda.TfsSpotlight.TFS
{
    /// <summary>The purpose of this class is to onform the user that there are credencials needed</summary>
    [Author("Bartłomiej Legiędź")]
    [Pluggable("NotifyAuthenticationNeededCredencialsProvider")]
    public class NotifyAuthenticationNeededCredencialsProvider : ICredentialsProvider
    {
        private readonly UICredentialsProvider _provider;
        private ICredentials _providedCredentials;
        private IMonitService MonitService { get; set; }
        private IIsolatedStorageService IsolatedStorageService { get; set; }

        public NotifyAuthenticationNeededCredencialsProvider(IMonitService monitService, IIsolatedStorageService isolatedStorageService)
        {
            this.MonitService = monitService;
            this.IsolatedStorageService = isolatedStorageService;
            this._provider = new UICredentialsProvider();
        }

        ICredentials ICredentialsProvider.GetCredentials(Uri uri, ICredentials failedCredentials)
        {
            var storedCredentials = GetUserCredentials(uri);
            if (storedCredentials != null)
            {
                return storedCredentials;
            }

            this.MonitService.ShowStatusMessage(String.Format(Messages.MsgCredentialsNeeded, uri), MessageSeverity.Information);
            this._providedCredentials = (this._provider as ICredentialsProvider).GetCredentials(uri, failedCredentials);
            this.MonitService.ClearStatusMessage();
            return this._providedCredentials;
        }

        void ICredentialsProvider.NotifyCredentialsAuthenticated(Uri uri)
        {
            SaveUserCredentials(uri);
            (this._provider as ICredentialsProvider).NotifyCredentialsAuthenticated(uri);
        }

        private void SaveUserCredentials(Uri uri)
        {
            if (!(this._providedCredentials is NetworkCredential)) return;

            var credentials = this._providedCredentials as NetworkCredential;
            if (credentials == null) return;

            var encryptedPassword = Cryptographer.EncryptSymmetric("DPAPI Symmetric Cryptography Provider", credentials.Password);
            var userCredentials = new UserCredential(uri.ToString(), credentials.Domain, credentials.UserName, encryptedPassword);

            this.IsolatedStorageService.Save(userCredentials, GetCredentialsFileName(uri));
        }

        private NetworkCredential GetUserCredentials(Uri uri)
        {
            var userCredentials = this.IsolatedStorageService.Load<UserCredential>(GetCredentialsFileName(uri));
            if (userCredentials == null) return null;

            var password = Cryptographer.DecryptSymmetric("DPAPI Symmetric Cryptography Provider", userCredentials.Password);
            return new NetworkCredential(userCredentials.UserName, password, userCredentials.Domain);
        }

        private static string GetCredentialsFileName(Uri uri)
        {
            return String.Format("{0}.{1}.credentials", uri.Host, uri.Port);
        }
    }
}
